package easy

import (
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"math"
	"reflect"
)

type reader interface {
	io.Reader
	ReadBytes(n int) (data []byte, err error)
	Byte() byte
}

type writer interface {
	io.Writer
	PutByte(b byte)
}

type EndianRead struct {
	endian binary.ByteOrder //数据编码模式
	reader
}

func (m *EndianRead) Int64() int64 {
	return int64(m.Uint64())
}

func (m *EndianRead) Uint64() uint64 {
	data, err := m.ReadBytes(8)
	if err != nil {
		panic(err)
	}
	val := m.endian.Uint64(data)
	return val
}

func (m *EndianRead) Int32() int32 {
	return int32(m.Uint32())
}

func (m *EndianRead) Uint32() uint32 {
	data, err := m.ReadBytes(4)
	if err != nil {
		panic(err)
	}
	val := m.endian.Uint32(data)
	return val
}

func (m *EndianRead) Int16() int16 {
	return int16(m.Uint16())
}

func (m *EndianRead) Uint16() uint16 {
	data, err := m.ReadBytes(2)
	if err != nil {
		panic(err)
	}
	val := m.endian.Uint16(data)
	return val
}

func (m *EndianRead) Float32() float32 {
	return math.Float32frombits(m.Uint32())
}

func (m *EndianRead) Float64() float64 {
	return math.Float64frombits(m.Uint64())
}

// 读取一批数据
func (m *EndianRead) ReadAny(p ...any) (n int) {
	for i, v := range p {
		switch f := v.(type) {
		case *bool:
			b := m.Byte()
			if b == 0 {
				*f = false
			} else {
				*f = true
			}
			n++
		case *float32:
			*f = m.Float32()
			n += 4
		case *float64:
			*f = m.Float64()
			n += 8
		case *int8:
			*f = int8(m.Byte())
			n++
		case *int16:
			*f = m.Int16()
			n += 2
		case *int32:
			*f = m.Int32()
			n += 4
		case *int64:
			*f = m.Int64()
			n += 8
		case *uint8:
			*f = m.Byte()
			n++
		case *uint16:
			*f = m.Uint16()
			n += 2
		case *uint32:
			*f = m.Uint32()
			n += 4
		case *uint64:
			*f = m.Uint64()
			n += 8
		case *[]byte:
			n, _ = m.Read(*f)
		default:
			t := reflect.TypeOf(f)
			panic(fmt.Sprintf("第 %d 个参数 [%s] 格式不支持", i+1, t.Kind().String()))
		}
	}
	return n
}

type EndianWrite struct {
	endian binary.ByteOrder //数据编码模式
	writer
}

func (m *EndianWrite) PutInt64(val int64) {
	m.PutUint64(uint64(val))
}

func (m *EndianWrite) PutUint64(val uint64) {
	var data [8]byte
	m.endian.PutUint64(data[:], val)
	_, err := m.Write(data[:])
	if err != nil {
		panic(err)
	}
}

func (m *EndianWrite) PutInt32(val int32) {
	m.PutUint32(uint32(val))
}

func (m *EndianWrite) PutUint32(val uint32) {
	var data [4]byte
	m.endian.PutUint32(data[:], val)
	_, err := m.Write(data[:])
	if err != nil {
		panic(err)
	}
}

func (m *EndianWrite) PutInt16(val int16) {
	m.PutUint16(uint16(val))
}

func (m *EndianWrite) PutUint16(val uint16) {
	var data [2]byte
	m.endian.PutUint16(data[:], val)
	_, err := m.Write(data[:])
	if err != nil {
		panic(err)
	}
}
func (m *EndianWrite) PutFloat32(val float32) {
	m.PutUint32(math.Float32bits(val))
}

func (m *EndianWrite) PutFloat64(val float64) {
	m.PutUint64(math.Float64bits(val))
}

// 写入一批数据
func (m *EndianWrite) WriteAny(p ...any) (n int) {
	for i, v := range p {
		switch f := v.(type) {
		case bool:
			if f {
				m.PutByte(1)
			} else {
				m.PutByte(0)
			}
			n++
		case float32:
			n += 4
			m.PutFloat32(f)
		case float64:
			n += 8
			m.PutFloat64(f)
		case int8:
			m.PutByte(byte(f))
			n++
		case int16:
			m.PutInt16(f)
			n += 2
		case int32:
			m.PutInt32(f)
			n += 4
		case int64:
			m.PutInt64(f)
			n += 8
		case uint8:
			m.PutByte(f)
			n++
		case uint16:
			m.PutUint16(f)
			n += 2
		case uint32:
			m.PutUint32(f)
			n += 4
		case uint64:
			m.PutUint64(f)
			n += 8
		case []byte:
			num, _ := m.Write(f)
			n += num
		case string:
			num, _ := m.Write([]byte(f))
			n += num
		default:
			t := reflect.TypeOf(f)
			panic(fmt.Sprintf("第 %d 个参数 [%s] 格式不支持", i+1, t.Kind().String()))
		}
	}
	return
}

type Reader struct {
	r io.Reader
	reader
}

func NewReader(r io.Reader) *Reader {
	m := new(Reader)
	m.r = r
	m.reader = m
	return m
}

func (m *Reader) ReadBytes(n int) (data []byte, err error) {
	data = make([]byte, n)
	i := 0
	idx := 0
	invalidCnt := 0
	for idx < n {
		i, err = m.r.Read(data[idx:])
		if err != nil {
			return
		}
		if i == 0 {
			invalidCnt++
			if invalidCnt > 100 {
				err = errors.New("read length always 0")
				return
			}
		}
		idx += i
		invalidCnt = 0
	}
	return
}
func (m *Reader) Byte() byte {
	data, err := m.ReadBytes(1)
	if err != nil {
		panic(err)
	}
	return data[0]
}

type Writer struct {
	w io.Writer
	writer
}

func NewWriter(w io.Writer) *Writer {
	m := new(Writer)
	m.w = w
	m.writer = m
	return m
}

func (m *Writer) PutByte(b byte) {
	_, err := m.w.Write([]byte{b})
	if err != nil {
		panic(err)
	}
}
